package proxy

import (
	"bytes"
	"cloud_android_backend/pkg/models/country"
	proxy2 "cloud_android_backend/pkg/models/proxy"
	"cloud_android_backend/pkg/models/resources"
	"fmt"
	"github.com/lucasjones/reggen"
	"github.com/speps/go-hashids/v2"
	"io"
	"log"
	"math/rand"
	"modules.tenxcloud.com/common/composite"
	"os"
	"os/exec"
	"os/signal"
	"strings"
	"syscall"
	"time"
)

func ProcessClash(instanceUseId int64) error {
	db, err := composite.Database.GetOrm()
	if err != nil {
		log.Printf("Error getting database: %v", err)
		return err
	}

	InstanceUseModel := resources.InstanceUses{Id: instanceUseId}
	err = InstanceUseModel.GetByIdWithInstanceInfo(db)
	if err != nil {
		return err
	}
	udid := fmt.Sprintf("%s:%d", InstanceUseModel.Instances.Machine.Ip, InstanceUseModel.Instances.AdbPort)
	err = InstallClash(udid)
	if err != nil {
		log.Printf("Error installing clash: %v", err)
		return err
	}
	if InstanceUseModel.ProxyId == 0 {
		log.Printf("Error proxyId is 0")
		return fmt.Errorf("proxyId is 0")
	}
	proxyModel := &proxy2.Proxy{Id: InstanceUseModel.ProxyId}
	err = proxyModel.GetById(db)
	if err != nil {
		log.Printf("Error getting proxy: %v", err)
		return err
	}
	hashid, err := getHashId(proxyModel.Id)
	if err != nil {
		log.Printf("Error getting hashid: %v", err)
		return err
	}
	// 随机端口 30000–50000
	port := pickRandomPort(30000, 50000)
	fmt.Printf("Selected port: %d\n", port)

	// 启动 Appium
	appiumPath := "/root/.nvm/versions/node/v18.20.8/bin/appium" // 或者你系统中的完整路径
	args := []string{
		"--port", fmt.Sprintf("%d", port),
		"--use-plugins=inspector",
		"--allow-cors",
		"--allow-insecure=adb_shell",
	}

	cmdAppium := exec.Command(appiumPath, args...)
	fmt.Printf("Starting Appium with Path: %v\n", "PATH="+os.Getenv("PATH"))
	cmdAppium.Env = append(os.Environ(),
		"PATH=/root/.nvm/versions/node/v18.20.8/bin:"+os.Getenv("PATH"),
		"ANDROID_HOME=/root/Android/Sdk",
		"ANDROID_SDK_ROOT=/root/Android/Sdk",
		"PATH="+os.Getenv("PATH")+":/root/.nvm/versions/node/v18.20.8/bin:/root/Android/Sdk/platform-tools",
	)
	// 可选：把输出重定向到 stdout/stderr，便于调试
	var out bytes.Buffer
	var stderr bytes.Buffer
	cmdAppium.Stdout = io.MultiWriter(os.Stdout, &out)
	cmdAppium.Stderr = io.MultiWriter(os.Stderr, &out)

	if err := cmdAppium.Start(); err != nil {
		log.Printf("Error starting Appium: %v", err)
		log.Printf("Appium output:\n%s\n", out.String())
		log.Printf("Appium stderr:\n%s\n", stderr.String())
		return err
	}
	fmt.Printf("Started Appium (pid=%d) on port %d\n", cmdAppium.Process.Pid, port)
	fmt.Printf("Appium output:\n%s\n", out.String())
	// 给一个短等待，确认端口已开启监听
	time.Sleep(2 * time.Second) // 或者更合适的等待逻辑
	// 确保在程序退出时关闭 Appium 进程
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	done := make(chan error, 1)

	appiumAddr := fmt.Sprintf("http://127.0.0.1:%d", port)
	go func() {
		// 等待 Python 脚本完成
		pythonPath := "python3.10"                                     // 或者 "python"
		pythonScript := "/home/project/cloud_android_backend/clash.py" // 替换为你的脚本路径
		pythonArgs := []string{pythonScript, udid, appiumAddr, hashid}
		cmdPython := exec.Command(pythonPath, pythonArgs...)
		cmdPython.Env = append(os.Environ(),
			//"PATH=/root/.nvm/versions/node/v18.20.8/bin:"+os.Getenv("PATH"),
			"ANDROID_HOME=/root/Android/Sdk",
			"ANDROID_SDK_ROOT=/root/Android/Sdk",
			"PATH="+os.Getenv("PATH")+":/root/.nvm/versions/node/v18.20.8/bin:/root/Android/Sdk/platform-tools",
		)
		cmdPython.Stdout = os.Stdout
		cmdPython.Stderr = os.Stderr

		fmt.Printf("Running Python script: %s %v\n", pythonPath, pythonArgs)
		if err := cmdPython.Run(); err != nil {
			done <- fmt.Errorf("python script failed: %w", err)
		} else {
			done <- nil
		}
	}()

	select {
	case err := <-done:
		if err != nil {
			log.Printf("Python script returned error: %v", err)
		} else {
			log.Printf("Python script completed successfully.")
		}
	case sig := <-quit:
		log.Printf("Got signal %v, exiting.", sig)
	}

	// 关闭 Appium 进程
	log.Printf("Stopping Appium (pid=%d)...", cmdAppium.Process.Pid)
	if err := cmdAppium.Process.Signal(syscall.SIGTERM); err != nil {
		log.Printf("Error sending SIGTERM to Appium: %v", err)
		// 强制杀掉
		if err2 := cmdAppium.Process.Kill(); err2 != nil {
			log.Printf("Error killing Appium process: %v", err2)
		}
	}
	// 等待 Appium 进程退出
	if err := cmdAppium.Wait(); err != nil {
		log.Printf("Appium process exit err: %v", err)
	} else {
		log.Printf("Appium process exited cleanly.")
	}

	log.Printf("Done.")
	return nil
}

func GetCountryParamsForInstance(instanceUseId int64) (map[string]string, error) {
	countryParams := make(map[string]string)
	db, err := composite.Database.GetOrm()
	if err != nil {
		return countryParams, err
	}
	InstanceUseModel := resources.InstanceUses{Id: instanceUseId}
	err = InstanceUseModel.GetByIdWithInstanceInfo(db)
	if err != nil {
		return countryParams, err
	}
	ProxyModel := &proxy2.Proxy{Id: InstanceUseModel.ProxyId}
	err = ProxyModel.GetById(db)
	if err != nil {
		return countryParams, err
	}
	//udid := fmt.Sprintf("%s:%d", InstanceUseModel.Instances.Machine.Ip, InstanceUseModel.Instances.AdbPort)
	CountryModel := country.CountryInfo{CountryCode: ProxyModel.CountryCode}
	err = CountryModel.GetCountryCode(db)
	if err != nil {
		return countryParams, err
	}
	simInfoModel := country.SimInfo{CountryCode: ProxyModel.CountryCode}
	list, err := simInfoModel.GetByCountryCode(db)
	if err != nil {
		return countryParams, err
	}
	len_ := len(list)
	// 设置随机种子，否则每次运行结果一样
	rand.Seed(time.Now().UnixNano())
	x := rand.Intn(len_ - 1)
	simInfo := list[x]
	mcc := simInfo.Mcc
	mnc := simInfo.Mnc
	phonenum, err := reggen.Generate(simInfo.PhoneRegex, 1)
	if err != nil {
		//return err
		fmt.Println(err)
	}
	countryParams["persist.sys.cloud.phonenum"] = phonenum
	iccid, err := reggen.Generate(simInfo.IccidRegex, 1)
	if err != nil {
		fmt.Println(err)
	}
	countryParams["persist.sys.cloud.iccidnum"] = iccid
	imei, err := reggen.Generate(simInfo.ImeiRegex, 1)
	if err != nil {
		fmt.Println(err)
	}
	countryParams["persist.sys.cloud.imeinum"] = imei
	imsi, err := reggen.Generate(simInfo.ImsiRegex, 1)
	if err != nil {
		fmt.Println(err)
	}
	countryParams["persist.sys.cloud.imsinum"] = imsi
	rand.Seed(time.Now().UnixNano())
	// 生成 [0, 0xFFF] 之间的随机整数
	n := rand.Intn(0x1000)
	tac := fmt.Sprintf("%03X", n)
	rand.Seed(time.Now().UnixNano())
	c := rand.Intn(0x10000000)
	cellid := fmt.Sprintf("%07X", c)
	rand.Seed(time.Now().UnixNano())
	e := rand.Intn(0x1000)
	narfcn := fmt.Sprintf("%03X", e)
	f := rand.Intn(0x100)
	physicalcellid := fmt.Sprintf("%02X", f)

	cellinfo := "9," + mcc + "," + mnc + "," + tac + "," + cellid + "," + narfcn + "," + physicalcellid
	countryParams["persist.sys.cloud.cellinfo"] = cellinfo

	if ProxyModel.Lat != "" {
		countryParams["persist.sys.cloud.gps.lat"] = ProxyModel.Lat
	}
	if ProxyModel.Lon != "" {
		countryParams["persist.sys.cloud.gps.lon"] = ProxyModel.Lon
	}
	countryParams["persist.sys.cloud.gps.speed"] = "0.1"
	countryParams["persist.sys.cloud.gps.altitude"] = "15"
	countryParams["persist.sys.cloud.gps.bearing"] = "73"
	if ProxyModel.Timezone != "" {
		countryParams["persist.sys.timezone"] = ProxyModel.Timezone
	}
	countryParams["persist.sys.cloud.mobileinfo"] = mcc + "," + mnc
	countryParams["ro.sys.cloud.proxy.type"] = ProxyModel.Protocol
	countryParams["ro.sys.cloud.proxy.mode"] = "vpn"
	countryParams["ro.sys.cloud.proxy.data"] = fmt.Sprintf("%s|%d|%s|%s|true", ProxyModel.Host, ProxyModel.Port, ProxyModel.UserName, ProxyModel.Password)
	return countryParams, nil
}
func pickRandomPort(min, max int) int {
	rand.Seed(time.Now().UnixNano())
	return rand.Intn(max-min+1) + min
}

func getHashId(id int) (string, error) {
	hd := hashids.NewData()
	hd.Salt = HashIdsSalt // 盐值决定编码结果
	hd.MinLength = 8      // 最短长度
	h, err := hashids.NewWithData(hd)
	if err != nil {
		fmt.Println(err)
		return "", err
	}
	// 编码
	encoded, err := h.EncodeInt64([]int64{int64(id)})
	if err != nil {
		fmt.Println(err)
		return "", err
	}
	return encoded, nil
}

func InstallClash(udid string) error {
	checkExits := func() bool {
		cmd := exec.Command("adb", "-s", udid, "shell", "pm", "list", "package")
		output, err := cmd.CombinedOutput()
		if err != nil {
			log.Printf("Error checking Clash installation: %v", err)
			return false
		}
		if strings.Contains(string(output), "com.github.kr328.clash") {
			log.Printf("Clash is already installed.")
			return true
		}
		return false
	}
	if checkExits() {
		return nil
	}
	cmd2 := exec.Command("adb", "-s", udid, "install", "-r", "/root/cfa-2.5.12.apk")
	output2, err := cmd2.CombinedOutput()
	if err != nil {
		log.Printf("Error installing Clash: %v", err)
		log.Printf("Output: %s", output2)
		return err
	}
	for i := 0; i < 10; i++ {
		time.Sleep(time.Second * 5)
		if checkExits() {
			log.Printf("Clash installed successfully.")
			return nil
		}
	}
	return fmt.Errorf("install clash timeout")
}
